package avicit.bdp.dgs.mdm.service;

import avicit.bdp.common.base.BaseService;
import avicit.bdp.common.utils.BdpLogUtil;
import avicit.bdp.dgs.mdm.dao.MdataInterfaceDao;
import avicit.bdp.dgs.mdm.dto.*;
import avicit.bdp.dgs.mdm.utils.api.HttpUtil;
import avicit.bdp.dgs.mdm.utils.enums.DataFlow;
import avicit.bdp.dgs.mdm.utils.enums.EnableState;
import avicit.bdp.dgs.mdm.utils.enums.PushStatus;
import avicit.platform6.commons.utils.ComUtil;
import avicit.platform6.commons.utils.PojoUtil;
import avicit.platform6.core.exception.BusinessException;
import avicit.platform6.core.exception.DaoException;
import avicit.platform6.core.properties.PlatformConstant;
import avicit.platform6.core.rest.msg.QueryRespBean;
import avicit.platform6.modules.system.syslog.service.SysLogUtil;
import com.alibaba.fastjson2.JSON;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.Map;

/**
 * @金航数码科技有限责任公司
 * @作者：${tableInfo.classCreator}
 * @邮箱：${tableInfo.classMailbox}
 * @创建时间： 2023-12-06 11:02
 * @类说明：
 * @修改记录：
 */
@Service
public class MdataInterfaceService extends BaseService<MdataInterfaceDao, MdataInterfaceDTO> {

    private static final Logger logger = LoggerFactory.getLogger(MdataInterfaceService.class);

    @Autowired
    private MdataInterfaceDao mdataInterfaceDao;
    @Autowired
    private MdataApplicationService mdataApplicationService;
    @Autowired
    private MdataMonitorService mdataMonitorService;
    @Autowired
    private MdataLogService mdataLogService;
    @Autowired
    private MdataRInterfaceService mdataRInterfaceService;
    @Autowired
    private MdataChangeService mdataChangeService;

    /**
     * 分页查询
     * @param keyWords
     * @param pageNo
     * @param pageSize
     * @return
     * @throws Exception
     */
    @Transactional(readOnly = true)
    public QueryRespBean<MdataInterfaceDTO> getPageList(String keyWords, String applicationId, Integer pageNo, Integer pageSize)
            throws Exception {
        QueryRespBean<MdataInterfaceDTO> queryRespBean = new QueryRespBean<>();
        PageHelper.startPage(pageNo, pageSize);
        Page<MdataInterfaceDTO> pageList = mdataInterfaceDao.getPageList(keyWords, applicationId);
        valueConvert(pageList.getResult());
        queryRespBean.setResult(pageList);
        BdpLogUtil.log4Query(queryRespBean);
        return queryRespBean;
    }

    private void valueConvert(List<MdataInterfaceDTO> interfaceList) {
        if (CollectionUtils.isNotEmpty(interfaceList)) {
            for (MdataInterfaceDTO obj : interfaceList) {
                obj.setStatusName(EnableState.getDescByCode(obj.getStatus()));
                obj.setDataFlowName(DataFlow.getDescByCode(obj.getDataFlow()));

                if(obj.getStatus() == EnableState.DISABLE.getCode()){
                    obj.setPushButton("0");
                    continue;
                }

                // 组装待推送的数据
                List<MdataRInterfaceDTO> mdataList = mdataRInterfaceService.queryList(obj.getId());
                Map<String, Object> map = mdataMonitorService.getPushData(obj.getApplicationId(), mdataList, obj.getDataSize(), null);
                if(map.size() == 0){
                    obj.setPushButton("0");
                }else{
                    obj.setPushButton("1");
                }
            }
        }
    }

    /**
     * 新增对象
     *
     * @param dto 保存对象
     * @return String
     */
    @Transactional
    public String save(MdataInterfaceDTO dto) {
        try {
            dto.setId(ComUtil.getId());
            PojoUtil.setSysProperties(dto, PlatformConstant.OpType.insert);
            dto.setStatus(0);
            this.insert(dto);
            // 记录日志
            SysLogUtil.log4Insert(dto);
            return dto.getId();
        } catch (Exception e) {
            throw new DaoException(e.getMessage(), e);
        }
    }

    /**
     * 修改对象部分字段
     *
     * @param dto 修改对象
     * @return int
     */
    @Transactional
    public int update(MdataInterfaceDTO dto) {
        try {
            int count = this.updateByPrimaryKey(getUpdateDto(dto));
            if (count == 0) {
                throw new DaoException("数据失效，请重新更新");
            }
            return count;
        } catch (Exception e) {
            throw new DaoException(e.getMessage(), e);
        }
    }

    /**
     * 通过主键查询单条记录
     *
     * @param id 主键id
     */
    @Transactional(readOnly = true)
    public MdataInterfaceDTO queryById(String id) {
        try {
            MdataInterfaceDTO dto = this.selectByPrimaryKey(id);
            // 记录日志
            if (dto != null) {
                SysLogUtil.log4Query(dto);
                dto.setStatusName(EnableState.getDescByCode(dto.getStatus()));
                dto.setDataFlowName(DataFlow.getDescByCode(dto.getDataFlow()));

                MdataApplicationDTO applicationDTO = mdataApplicationService.selectByPrimaryKey(dto.getApplicationId());
                if(applicationDTO != null){
                    dto.setApplicationName(applicationDTO.getName());
                }
            }
            return dto;
        } catch (Exception e) {
            throw new DaoException(e.getMessage(), e);
        }
    }

    /**
     * 删除
     */
    @Transactional
    public void deleteById(MdataInterfaceDTO dto){
        if (StringUtils.isEmpty(dto.getId())) {
            throw new BusinessException("id不能为空");
        }

        String[] idArr = dto.getId().split(",");
        for(String id : idArr){
            mdataRInterfaceService.deleteMdataByInterfaceId(id);
            this.deleteByPrimaryKey(id);
        }
    }

    /**
     * 内部方法，获取修改的dto对象
     *
     * @param dto
     * @return
     */
    private MdataInterfaceDTO getUpdateDto(MdataInterfaceDTO dto) {
        MdataInterfaceDTO oldDTO = this.selectByPrimaryKey(dto.getId());
        if (oldDTO == null) {
            throw new DaoException("数据不存在");
        }
        //记录日志
        SysLogUtil.log4Update(dto, oldDTO);
        PojoUtil.setSysProperties(dto, PlatformConstant.OpType.update);
        PojoUtil.copyProperties(oldDTO, dto, true);
        return oldDTO;
    }

    /**
     * 启用停用
     */
    @Transactional
    public void updateStatus(MdataInterfaceDTO dto){
        if (StringUtils.isEmpty(dto.getId())) {
            throw new BusinessException("id不能为空");
        }

        String[] idArr = dto.getId().split(",");
        List<String> idList = Arrays.asList(idArr);
        mdataInterfaceDao.updateStatus(idList, dto.getStatus());
    }

    /**
     * 查询接口列表
     *
     */
    @Transactional(readOnly = true)
    public List<MdataInterfaceDTO> queryList(String applicationId) {
        MdataInterfaceDTO dto = new MdataInterfaceDTO();
        dto.setApplicationId(applicationId);
        dto.setStatus(EnableState.ENABLE.getCode());
        return this.selectList(dto);
    }

    /**
     * 推送数据
     */
    @Transactional
    public Boolean pushData(MdataInterfaceDTO dto){
        boolean result = false;
        String interfaceId = dto.getId();
        if (StringUtils.isEmpty(interfaceId)) {
            throw new BusinessException("id不能为空");
        }

        // 验证接口和系统合法性
        MdataInterfaceDTO interfaceDTO = this.selectByPrimaryKey(interfaceId);
        if (interfaceDTO == null) {
            throw new DaoException("接口数据不存在");
        }
        if(interfaceDTO.getStatus() != EnableState.ENABLE.getCode()){
            throw new BusinessException("接口未启用");
        }
        MdataApplicationDTO applicationDTO = mdataApplicationService.selectByPrimaryKey(interfaceDTO.getApplicationId());
        if (applicationDTO == null) {
            throw new DaoException("所属系统不存在");
        }
        if(applicationDTO.getStatus() != EnableState.ENABLE.getCode()){
            throw new BusinessException("所属系统未启用");
        }

        // 组装待推送的数据
        List<MdataRInterfaceDTO> mdataList = mdataRInterfaceService.queryList(interfaceId);
        Map<String, Object> map = mdataMonitorService.getPushData(applicationDTO.getId(), mdataList, interfaceDTO.getDataSize(), null);
        if(map.size() == 0){
            throw new BusinessException("没有待推送的数据");
        }
        String data = (String) map.get("data");
        List<String> monitorIdList = (List<String>) map.get("monitorIdList");
        String monitorIds = JSON.toJSONString(monitorIdList);

        // 调用接口前记录日志
        String logId = saveLog(interfaceId, applicationDTO.getId(), data, monitorIds);

        // 调用接口推送
        String url = applicationDTO.getServicePath() + interfaceDTO.getAddress();
        logger.info("请求方法:{}, 调用的接口是:{}", interfaceDTO.getMethod(), url);
        int callStatus = 1;
        String callResult = "调用成功";
        try{
            // 更新推送状态和时间-推送中
            mdataMonitorService.updatePushStatusAndTimeById(PushStatus.PUSHING.getCode(), new Date(), monitorIdList);

            HttpUtil httpUtil = new HttpUtil(interfaceDTO.getMethod(), interfaceDTO.getTimeout());
            httpUtil.remoteCallApi(applicationDTO.getCode(), applicationDTO.getAuthCode(), logId, data, url);
            result = true;
            logger.info("调用接口成功");
        }catch (Exception e){
            e.printStackTrace();
            callStatus = 2;
            callResult = "调用失败," + e.getMessage();
            // 更新推送状态和时间-推送失败
            mdataMonitorService.updatePushStatusAndTimeById(PushStatus.PUSH_FAIL.getCode(), new Date(), monitorIdList);
            result = false;
            logger.info("调用接口失败");
        }

        // 调用接口后更新日志
        updateLog(logId, callStatus, callResult);
        return result;
    }

    /**
     * 推送单条数据
     */
    @Transactional
    public Boolean pushDataById(String monitorId){
        boolean result = false;
        if (StringUtils.isEmpty(monitorId)) {
            throw new BusinessException("id不能为空");
        }
        MdataMonitorDTO mdataMonitor = mdataMonitorService.selectByPrimaryKey(monitorId);
        if (mdataMonitor == null) {
            throw new DaoException("监控数据不存在");
        }
        MdataChangeDTO mdataChange = mdataChangeService.selectByPrimaryKey(mdataMonitor.getChangeId());
        if (mdataChange == null) {
            throw new DaoException("变更数据不存在");
        }
        mdataChange.setMonitorId(monitorId);
        String applicationId = mdataMonitor.getApplicationId();
        String mdataId = mdataChange.getMdataId();

        // 验证接口和系统合法性
        MdataInterfaceDTO interfaceDTO = mdataInterfaceDao.getMdataInterface(applicationId, mdataId);
        if (interfaceDTO == null) {
            throw new DaoException("接口数据不存在");
        }
        if(interfaceDTO.getStatus() != EnableState.ENABLE.getCode()){
            throw new BusinessException("接口未启用");
        }
        MdataApplicationDTO applicationDTO = mdataApplicationService.selectByPrimaryKey(interfaceDTO.getApplicationId());
        if (applicationDTO == null) {
            throw new DaoException("所属系统不存在");
        }
        if(applicationDTO.getStatus() != EnableState.ENABLE.getCode()){
            throw new BusinessException("所属系统未启用");
        }
        String interfaceId = interfaceDTO.getId();

        // 组装待推送的数据
        List<MdataRInterfaceDTO> mdataList = mdataRInterfaceService.queryList(interfaceId, mdataId);
        Map<String, Object> map = mdataMonitorService.getPushData(applicationDTO.getId(), mdataList, interfaceDTO.getDataSize(), mdataChange);
        if(map.size() == 0){
            throw new BusinessException("没有待推送的数据");
        }
        String data = (String) map.get("data");
        List<String> monitorIdList = (List<String>) map.get("monitorIdList");
        String monitorIds = JSON.toJSONString(monitorIdList);

        // 调用接口前记录日志
        String logId = saveLog(interfaceId, applicationDTO.getId(), data, monitorIds);

        // 调用接口推送
        String url = applicationDTO.getServicePath() + interfaceDTO.getAddress();
        logger.info("请求方法:{}, 调用的接口是:{}", interfaceDTO.getMethod(), url);
        int callStatus = 1;
        String callResult = "调用成功";
        try{
            // 更新推送状态和时间-推送中
            mdataMonitorService.updatePushStatusAndTimeById(PushStatus.PUSHING.getCode(), new Date(), monitorIdList);

            HttpUtil httpUtil = new HttpUtil(interfaceDTO.getMethod(), interfaceDTO.getTimeout());
            httpUtil.remoteCallApi(applicationDTO.getCode(), applicationDTO.getAuthCode(), logId, data, url);
            result = true;
            logger.info("调用接口成功");
        }catch (Exception e){
            e.printStackTrace();
            callStatus = 2;
            callResult = "调用失败," + e.getMessage();
            // 更新推送状态和时间-推送失败
            mdataMonitorService.updatePushStatusAndTimeById(PushStatus.PUSH_FAIL.getCode(), new Date(), monitorIdList);
            result = false;
            logger.info("调用接口失败");
        }

        // 调用接口后更新日志
        updateLog(logId, callStatus, callResult);
        return result;
    }

    /**
     * 保存调用日志
     * @param interfaceId
     * @param applicationId
     * @param data
     * @return
     */
    private String saveLog(String interfaceId, String applicationId, String data, String monitorIds){
        MdataLogDTO mdataLog = new MdataLogDTO();
        mdataLog.setInterfaceId(interfaceId);
        mdataLog.setApplicationId(applicationId);
        mdataLog.setCallBeginTime(new Date());
        mdataLog.setData(data);
        mdataLog.setMonitorIds(monitorIds);
        return mdataLogService.save(mdataLog);
    }

    /**
     * 更新调用日志
     * @param logId
     * @param callStatus
     * @param callResult
     */
    private void updateLog(String logId, int callStatus, String callResult){
        MdataLogDTO mdataLog = new MdataLogDTO();
        mdataLog.setId(logId);
        mdataLog.setCallStatus(callStatus);
        mdataLog.setCallEndTime(new Date());
        mdataLog.setCallResult(callResult);
        mdataLogService.update(mdataLog);
    }

    public long selectCountByAppId(String applicationId){
        MdataInterfaceDTO dto = new MdataInterfaceDTO();
        dto.setApplicationId(applicationId);
        return this.selectCount(dto);
    }

}
